using System;
using NUnit.Framework;
using dnA.Math;
using dnA.Exceptions;

namespace dnA.dnAtests.Math {
	[TestFixture]
	public class ComplexDoubleSVDDecompTest {
		private static ComplexDoubleSVDDecomp svd;
		private static ComplexDoubleSVDDecomp lsvd;
		private static ComplexDoubleSVDDecomp wsvd;
		private const double TOLERENCE = 0.01;

		static ComplexDoubleSVDDecompTest(){		
			ComplexDoubleMatrix a = new ComplexDoubleMatrix(3);
			a[0,0] = new ComplexDouble(1.1, 1.1);
			a[0,1] = new ComplexDouble(2.2, -2.2);
			a[0,2] = new ComplexDouble(3.3, 3.3);
			a[1,0] = new ComplexDouble(4.4, -4.4);
			a[1,1] = new ComplexDouble(5.5, 5.5);
			a[1,2] = new ComplexDouble(6.6, -6.6);
			a[2,0] = new ComplexDouble(7.7, 7.7);
			a[2,1] = new ComplexDouble(8.8, -8.8);
			a[2,2] = new ComplexDouble(9.9, 9.9);
			svd = new ComplexDoubleSVDDecomp(a);
			
			a = new ComplexDoubleMatrix(2,4);
			a[0,0] = new ComplexDouble(1.1, 1.1);
			a[0,1] = new ComplexDouble(2.2, -2.2);
			a[0,2] = new ComplexDouble(3.3, 3.3);
			a[0,3] = new ComplexDouble(4.4, -4.4);
			a[1,0] = new ComplexDouble(5.5, 5.5);
			a[1,1] = new ComplexDouble(6.6, -6.6);
			a[1,2] = new ComplexDouble(7.7, 7.7);
			a[1,3] = new ComplexDouble(8.8, -8.8);

			wsvd = new ComplexDoubleSVDDecomp(a);
				
			a = new ComplexDoubleMatrix(4,2);
			a[0,0] = new ComplexDouble(1.1, 1.1);
			a[0,1] = new ComplexDouble(2.2, -2.2);
			a[1,0] = new ComplexDouble(3.3, 3.3);
			a[1,1] = new ComplexDouble(4.4, -4.4);
			a[2,0] = new ComplexDouble(5.5, 5.5);
			a[2,1] = new ComplexDouble(6.6, -6.6);
			a[3,0] = new ComplexDouble(7.7, 7.7);
			a[3,1] = new ComplexDouble(8.8, -8.8);
				
			lsvd = new ComplexDoubleSVDDecomp(a);
		}
		/*[Test]
		public void UTest(){
			Assert.AreEqual(svd.U.ColumnLength,3);
			Assert.AreEqual(svd.U.RowLength,3);
			Assert.AreEqual(System.Math.Abs(svd.U[0,1].Real),0.04,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,0].Real),0.17,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,1].Real),0.04,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,2].Real),0.69,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,0].Real),0.21,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,1].Real),0.68,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,2].Real),0.01,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,0].Real),0.65,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,1].Real),0.20,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,2].Real),0.17,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,0].Imag),0.17,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,1].Imag),0.04,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,2].Imag),0.69,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,0].Imag),0.21,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,1].Imag),0.68,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,2].Imag),0.01,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,0].Imag),0.65,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,1].Imag),0.20,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,2].Imag),0.17,TOLERENCE);		
		}

		[Test]
		public void VTest(){
			Assert.AreEqual(svd.V.ColumnLength,3);
			Assert.AreEqual(svd.V.RowLength,3);
			Assert.AreEqual(System.Math.Abs(svd.V[0,0].Real),0.531,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,1].Real),0.221,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,2].Real),0.818,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,0].Real),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,1].Real),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,2].Real),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,0].Real),0.728,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,1].Real),0.375,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,2].Real),0.574,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,1].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,2].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,0].Imag),0.43,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,1].Imag),0.90,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,2].Imag),0.04,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,1].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,2].Imag),0,TOLERENCE);		}
*/
		[Test]
		public void STest(){
			Assert.AreEqual(svd.S[0,0],23.088,TOLERENCE);
			Assert.AreEqual(svd.S[1,1],12.417,TOLERENCE);
			Assert.AreEqual(svd.S[2,2],1.576,TOLERENCE);
		}

/*
		[Test]
		public void LUTest(){
			Assert.AreEqual(lsvd.U.ColumnLength,4);
			Assert.AreEqual(lsvd.U.RowLength,4);
			Assert.AreEqual(System.Math.Abs(lsvd.U[0,0].Real),0.11,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[0,1].Real),0.58,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[0,2].Real),0.37,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[0,3].Real),0.34,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,0].Real),0.25,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,1].Real),0.30,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[1,2].Real),0.21,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[1,3].Real),0.75,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,0].Real),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,1].Real),0.01,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[2,2].Real),0.68,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[2,3].Real),0.49,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,0].Real),0.53,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,1].Real),0.27,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[3,2].Real),0.52,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[3,3].Real),0.08,TOLERENCE);

			Assert.AreEqual(System.Math.Abs(lsvd.U[0,0].Imag),0.11,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[0,1].Imag),0.58,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[0,2].Imag),0.16,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[0,3].Imag),0.16,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,0].Imag),0.25,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,1].Imag),0.30,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[1,2].Imag),0.24,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[1,3].Imag),0.21,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,0].Imag),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,1].Imag),0.01,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[2,2].Imag),0.02,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[2,3].Imag),0.07,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,0].Imag),0.53,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,1].Imag),0.27,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[3,2].Imag),0.09,TOLERENCE);
			//			Assert.AreEqual(System.Math.Abs(lsvd.U[3,3].Imag),0.12,TOLERENCE);
		}

		[Test]
		public void LVTest(){
			Assert.AreEqual(lsvd.V.ColumnLength,2);
			Assert.AreEqual(lsvd.V.RowLength,2);
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,0].Real),0.641,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,1].Real),0.767,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,0].Real),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,1].Real),0,TOLERENCE);		
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,1].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,0].Imag),0.77,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,1].Imag),0.64,TOLERENCE);			
		}
*/		
		[Test]
		public void LSTest(){
			Assert.AreEqual(lsvd.S[0,0],22.198,TOLERENCE);
			Assert.AreEqual(lsvd.S[1,1],0.975,TOLERENCE);
		}

/*
		[Test]
		public void WUTest(){
			Assert.AreEqual(wsvd.U.ColumnLength,2);
			Assert.AreEqual(wsvd.U.RowLength,2);
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,0].Real),0.376,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,1].Real),0.927,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,0].Real),0.927,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,1].Real),0.376,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,1].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,1].Imag),0,TOLERENCE);
		}

		[Test]
		public void WVTest(){
			Assert.AreEqual(wsvd.V.ColumnLength,4);
			Assert.AreEqual(wsvd.V.RowLength,4);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,0].Real),0.25,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,1].Real),0.54,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,2].Real),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,3].Real),0.11,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,0].Real),0.31,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,1].Real),0.23,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,2].Real),0.19,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,3].Real),0.77,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,0].Real),0.38,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,1].Real),0.08,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,2].Real),0.67,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,3].Real),0.08,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,0].Real),0.44,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,1].Real),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,2].Real),0.08,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,3].Real),0.07,TOLERENCE);

			Assert.AreEqual(System.Math.Abs(wsvd.V[0,0].Imag),0.25,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,1].Imag),0.54,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,2].Imag),0.14,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,3].Imag),0.35,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,0].Imag),0.31,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,1].Imag),0.23,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,2].Imag),0.24,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,3].Imag),0.12,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,0].Imag),0.38,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,1].Imag),0.08,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,2].Imag),0.03,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,3].Imag),0.49,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,0].Imag),0.44,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,1].Imag),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,2].Imag),0.53,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,3].Imag),0.09,TOLERENCE);
		}
*/		
		[Test]
		public void WSTest(){
			Assert.AreEqual(System.Math.Abs(wsvd.S[0,0]),22.132,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.S[1,1]),1.956,TOLERENCE);
		}
		[Test]
		public void RankTest(){
			Assert.AreEqual(svd.Rank,3);
		}		

		[Test]
		public void ConditionTest(){
			Assert.AreEqual(svd.Condition,14.650,TOLERENCE);
		}		

		[Test]
		public void NormTest(){
			Assert.AreEqual(svd.Norm2,23.088,TOLERENCE);
		}		
		
		[Test]
		public void LRankTest(){
			Assert.AreEqual(lsvd.Rank,2);
		}
		
		[Test]
		public void LConditionTest(){
			Assert.AreEqual(lsvd.Condition,22.764,TOLERENCE);
		}
		
		[Test]
		public void LNormTest(){
			Assert.AreEqual(lsvd.Norm2,22.198,TOLERENCE);
		}

		[Test]
		public void WRankTest(){
			Assert.AreEqual(wsvd.Rank,2);
		}
		
		[Test]
		public void WConditionTest(){
			Assert.AreEqual(wsvd.Condition,11.316,TOLERENCE);
		}
		
		[Test]
		public void WNormTest(){
			Assert.AreEqual(wsvd.Norm2,22.133,TOLERENCE);
		}
	}
}

